//---HEADER
//	Name:	Haptik Library
//	Desc:	Component Based Haptic Devices Access Library
//	Auto:	Maurizio de Pascale
//	Date:	July 17th 2005
//	Tabs:	tabbed at 3
//	Http:	www.haptiklibrary.org
//	Svns:	$Revision: 39 $
//			$Date: 2005-12-03 16:24:01 +0100 (sab, 03 dic 2005) $
//------------------------------------------------------------>
#ifndef ___RSLIB_HAPTIK___
#define ___RSLIB_HAPTIK___
 
 
 
//---INCLUDE
//--------------------->
#include <RSLib_OLD/Types.hpp>
#include <RSLib_OLD/LowLevel.hpp>
#include <RSLib_OLD/Math/3D.hpp>
 
 
 
//---DLL IMPORT EXPORT
//------------------------------>
#ifdef RS_WINDOWS
#ifndef HAPTIK_DLL_IMPORT_EXPORT
	#pragma comment(lib,"Haptik.Library.lib")
	#define HAPTIK_DLL_IMPORT_EXPORT __declspec(dllimport)
#endif
#else
#endif

#ifdef RS_LINUX
	#ifndef HAPTIK_DLL_IMPORT_EXPORT
		#define HAPTIK_DLL_IMPORT_EXPORT 
	#endif
#endif
 
 
 
//---INTERFACE IDS
//----------------------------------------------->
#define HAPTIK_IHAPTIKLIBRARY				0x80008001
#define HAPTIK_IHAPTIKDEVICE				0x80008011
#define HAPTIK_IHAPTIKPLUGIN				0x80008031
 
 
 
//---MACRO
//------------------------------------------------------------------->
#define RELEASE_HAPTIK_INTERFACE(ptr) if(ptr){ptr->Release();ptr=NULL;}
 
 
 
//---FUNCTION
//	Desc: C-based entrypoint to retrieve IHaptikLibrary interfaces
//------------------------------------------------------------------------------------------------------------->
extern "C" HAPTIK_DLL_IMPORT_EXPORT PVOID GetHaptikLibraryInterface(IN UINT32 interfaceId = HAPTIK_IHAPTIKLIBRARY);
 
 
 
//---RETURN VALUES
//	Desc:	HRESULT-like return values.
//			Use the FAILED(ret) and SUCCEEDED(ret) macros
//---------------------------------------------------->
#define HAPTIK_SUCCESS						0x00000000
#define HAPTIK_WARNING						0x00000001
#define HAPTIK_ALREADY						0x00000001
#define HAPTIK_CALIBRATED					0x00000010
#define HAPTIK_NOTCALIBRATED				0x00000020
#define HAPTIK_ERROR							0x80000000
#define HAPTIK_FAILURE						0x80000000
#define HAPTIK_SDK_ERROR					0x80000001
#define HAPTIK_MEMORY_ERROR				0x80000002
#define HAPTIK_UNSUPPORTED					0x80000003
#define HAPTIK_OUT_OF_RANGE				0x80000004
#define HAPTIK_NO_SUCH_DEVICE				0x80000005
#define HAPTIK_NOT_INITIALIZED			0x80000006

 
 
 
//---DEVICE IDS
//----------------------------------------------->
#define HAPTIK_DEFAULT_DEVICE				0x80FFFFFF
#define HAPTIK_MOUSE_SPECTRE				0x80FF8001
#define HAPTIK_BETAMAX_PLAYER				0x80FF8002
#define HAPTIK_BETAMAX_RECORDER			0x80FF8003
#define HAPTIK_PHANTOM_PREMIUM			0x80FF4001
#define HAPTIK_PHANTOM_DESKTOP			0x80FF4002
#define HAPTIK_PHANTOM_OMNI				0x80FF4003
#define HAPTIK_PHANTOM_PREMIUM6D			0x80FF4004
#define HAPTIK_DELTA							0x80FFC001
#define HAPTIK_OMEGA							0x80FFC002
#define HAPTIK_FREEDOM6S					0x80FF2001
#define HAPTIK_CUBIC							0x80FF2002
 
 
 
namespace RSLib {
 
 
 
//---CLASS
//	Desc:	Describe library implementation
//-------------------------------------->
typedef class HaptikLibraryInfo
{
	public:
	PCHAR8 name;
	PCHAR8 company;
	PCHAR8 version;
	UINT32 versionNumbers[4];
	
	private:
	DWORD reserved[9];
}*HaptikLibraryInfoPtr;
 
 
 
//---CLASS
//	Desc:	Describe a plugin
//---------------------------->
typedef class HaptikPluginInfo
{
	public:
	PCHAR8 name;
	PCHAR8 company;
	PCHAR8 version;
	UINT32 versionNumbers[4];
	UINT32 numberOfDevices;
	
	private:
	DWORD reserved[8];
}*HaptikPluginInfoPtr;
 
 
 
//---CLASS
//	Desc:	Describe an installed device
//------------------------------------>
typedef class HaptikDeviceInfo
{
	public:
	UINT32 id;					//device unique id
	
	public:
	PCHAR8 name;				//device name
	PCHAR8 model;				//device model
	PCHAR8 manufacturer;		//device manifacturer
	
	public:
	BOOL32 ready;				//device ready
	
//	EXTENDED INFOS
	public:
//	Rate
	FLT32 currentRate;
	FLT32 defaultRate;
	FLT32 maxRate;
	FLT32 minRate;

//	Workspace
	FLT32 maxX;
	FLT32 maxY;
	FLT32 maxZ;
	FLT32 minX;
	FLT32 minY;
	FLT32 minZ;
	
//	Force Feedback
	FLT32 maxForceIntensity;
	FLT32 maxTorqueIntensity;
	
//	Buttons
	UINT32 numberOfButtons;
	
//	Hardware Capabilities
	UINT32 capabilities;
	
	private:
	DWORD reserved[4];
	
}*HaptikDeviceInfoArray,*HaptikDeviceInfoPtr;
 
 
 
//---CAPABILITIES
//	Desc:	If corresponding bit is set in the capabilities mask
//			then the device supports this feature in hardware
//--------------------------------------------------------->
#define HAPTIK_CAPABILITY_POSITION				0x00000001
#define HAPTIK_CAPABILITY_VELOCITY				0x00000002
#define HAPTIK_CAPABILITY_ORIENTATION			0x00000004
#define HAPTIK_CAPABILITY_FORCEFEEDBACK		0x00000010
#define HAPTIK_CAPABILITY_TORQUEFEEDBACK		0x00000020
#define HAPTIK_CAPABILITY_VARIABLE_RATE		0x00000100
 
 
 
//---CLASS
//	Desc:	Data exchanged with an IHaptikDevice 
//	Note:	This is only a template. You can define another struct 
//			using your classes for matrix/vector computations.
//			Memory layout and order should be preserved.
//			adding of "operator HaptikData&()" allows for unchanged syntax
//--------------------------------------------------------------------->
typedef class HaptikData
{
public:
//	Output from Device
	Math::Matrix4x4 matrix;
	Math::Vector3 position;
	Math::Vector3 velocity;
	UINT32 buttonMask;
	
private:
	DWORD reserved0[1];
	
public:
//	Input to Device
	Math::Vector3 forceFeedback;
	Math::Vector3 torqueFeedback;
	
private:
	DWORD reserved1[2];
	
public:
//	Helper Methods
	BOOL32 Button(UINT32 index = 0)	{return buttonMask & (1<<index);}
	
public:
	HaptikData()	{ZeroMemory(this,sizeof(*this));}
}*HaptikDataPtr;
 
 
 
//---STRUCT
//	Desc:	User Data exchanged with an IHaptikDevice
//	Note:	Applications can also ignore this data.
//---------------------------------------------->
typedef class HaptikUserData
{
public:
	DWORD userData;
	UINT32 lastError;
	
//	Make struct 32 bytes aligned and reserve space for extensions
private:
	DWORD reserved[6];
	
public:
	HaptikUserData()	{userData = 0;	lastError = HAPTIK_SUCCESS;}
}*HaptikUserDataPtr;
 
 
 
//---INTERFACE
//	Desc:	Interface exposed by the library component
//------------------------------------------------->
typedef class IHaptikLibrary
{
	public:
	virtual UINT32 Init(IN PVOID reserved = NULL) PURE;
	virtual UINT32 Release() PURE;
		
	virtual UINT32 GetNumberOfDevices() PURE;
	virtual UINT32 GetDeviceInfo(IN UINT32 deviceId,OUT HaptikDeviceInfo& info) PURE;
	virtual PVOID GetDeviceInterface(IN UINT32 deviceId = HAPTIK_DEFAULT_DEVICE,IN UINT32 interfaceId = HAPTIK_IHAPTIKDEVICE) PURE;
	
//	All methods below are reserved for future uses and will currently return HAPTIK_UNSUPPORTED
	virtual UINT32 GetNumberOfPlugins() PURE;
	virtual UINT32 GetPluginInfo(IN UINT32 pluginId,OUT HaptikPluginInfo& info) PURE;
	virtual PVOID GetPluginInterface(IN UINT32 pluginId,IN UINT32 interfaceId = HAPTIK_IHAPTIKPLUGIN) PURE;
	
	virtual UINT32 GetLibraryInfo(OUT HaptikLibraryInfo& info) PURE;
}*IHaptikLibraryInterface;
 
 
 
//---INTERFACE
//	Desc:	Represent a 6DOF haptic device
//------------------------------------->
typedef class IHaptikDevice
{
	public:
	virtual UINT32 Init(IN PVOID method = NULL,IN PVOID object = NULL) PURE;
	virtual UINT32 Release() PURE;
	
//	Control	
	virtual UINT32 Start() PURE;
	virtual UINT32 Stop() PURE;

//	Access
	virtual UINT32 Read(OUT HaptikData& data) PURE;
	virtual UINT32 Write(IN HaptikData& data) PURE;
	
//	Info & Configuration
	virtual UINT32 SetRate(IN FLT32 rateInHz) PURE;
	virtual FLT32 GetRate() PURE;
	virtual UINT32 GetInfo(OUT HaptikDeviceInfo& info) PURE;
	virtual UINT32 SetUserData(IN DWORD userData) PURE;
	virtual DWORD GetUserData() PURE;
	virtual UINT32 SetCallback(IN PVOID method = NULL,PVOID object = NULL, IN DWORD reserved = NULL) PURE;
	virtual UINT32 GetCallback(OUT PVOID& method,OUT PVOID& object = NULL_REFERENCE(PVOID),IN DWORD reserved = NULL) PURE;
	virtual UINT32 GetLastError() PURE;
	
//	Recalibration
	virtual UINT32 GetCalibrationStatus() PURE;
	virtual UINT32 Recalibrate(IN UINT32 reserved = NULL) PURE;
}*IHaptikDeviceInterface;
 
 
 
//---TYPEDEF
//	Desc:	Prototype for callbacks
//-------------------------------------------->
typedef VOID (*HaptikCallbackPtr)(HaptikData&);
typedef VOID (*HaptikCallbackExPtr)(HaptikData&,HaptikUserData&);
 
 
 
//---CLASS
//	Name:	Haptik
//	Desc:	C++ Wrapper Class around the IHaptikLibrary interface
//------------------------------------------------------------>
class Haptik
{
	public:
	UINT32 numberOfDevices;
	HaptikDeviceInfoArray device;
	IHaptikLibraryInterface library;
	
	public:
	Haptik()
	{
		device = NULL;
		numberOfDevices = 0;
		library = (IHaptikLibraryInterface)GetHaptikLibraryInterface();
		if (library)
		{
			library->Init(NULL);
			RefreshDeviceList();
		}
	//!TODO:	assert SDK version <= LIB version
	}
	~Haptik()
	{
		if (library)	library->Release();
		if (device)		delete[]device;
	}
	
	public:
	PVOID GetDeviceInterface(IN UINT32 deviceId = HAPTIK_DEFAULT_DEVICE,IN UINT32 interfaceId = HAPTIK_IHAPTIKDEVICE)
	{
		if (library)
		{
			PVOID interfacePtr = library->GetDeviceInterface(deviceId,interfaceId);
			RefreshDeviceList();
			return interfacePtr;
		}
		else return NULL;
	}
	UINT32 RefreshDeviceList()
	{
		if (library)
		{
			if (device)	delete[] device;
			numberOfDevices = library->GetNumberOfDevices();
			device = new HaptikDeviceInfo[numberOfDevices];
			for(UINT32 i=0 ; i<numberOfDevices ; i++)	library->GetDeviceInfo(i,device[i]);
			return HAPTIK_SUCCESS;
		}
		else return HAPTIK_UNSUPPORTED;
	}
	
	public:
	IHaptikDeviceInterface GetHaptikDeviceInterface(IN UINT32 deviceId = HAPTIK_DEFAULT_DEVICE)
	{
		return (IHaptikDeviceInterface)GetDeviceInterface(deviceId,HAPTIK_IHAPTIKDEVICE);
	}
	
	public:
	static PCHAR8 ResultToString(UINT32 result)
	{
		switch(result)
		{
			case HAPTIK_SUCCESS:
			return "Operation Completed Successfully";
			
			case HAPTIK_WARNING:
			return "Warning";
			
			case HAPTIK_ERROR:
			return "Generic Error";
			
			case HAPTIK_SDK_ERROR:
			return "An error has been reported from a device SDK";
			
			case HAPTIK_MEMORY_ERROR:
			return "A Memory Allocation Failed";
			
			case HAPTIK_UNSUPPORTED:
			return "Operation/Interface not Supported";
			
			case HAPTIK_OUT_OF_RANGE:
			return "Request is out of range";
			
			case HAPTIK_NO_SUCH_DEVICE:
			return "No such Device";
			
			case HAPTIK_NOT_INITIALIZED:
			return "Interface has not been initialized";
			
			default:
			return "Unknown Return Value";
		}
	}
};
 
 
 
}//namespace RSLib
 
 
 
#endif//__RSLIB_HAPTIK___